package org.juiceshop.musi.midi;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class MidiOutputStream extends DataOutputStream {

	/**
	 * Creates a new instance from an OutputStream.
	 * @param out The underlying <code>OutputStream</code>.
	 */
	public MidiOutputStream(OutputStream out) {
		super(out);
	}

	/**
	 * Creates a new Instance with a new ByteOutputStream as 
	 * underlying OutputStream.
	 * Use {@link #toByteArray()} or {@link #writeTo(MidiOutputStream)} to access
	 * written data.
	 */
	public MidiOutputStream() {
		this(new ByteArrayOutputStream());
	}
	
	/**
	 * 
	 * @param data
	 * @throws IOException
	 */
	public void writeBytes (int...data) throws IOException {
		for (int value : data) {
			writeByte(value);
		}
	}
	
	public void writeVariable(int value) throws IOException {
		byte[] buffer = new byte[5];
		int offset = buffer.length;
		buffer[--offset] = (byte)(value & 0x7F);
		while ((value>>=7) > 0) {
			buffer[--offset] = (byte)((value & 0x7F) | 0x80);
		};
		write(buffer, offset, buffer.length-offset);
	}
	
	public void writeHeader (int resolution, int numberOfTracks) throws IOException  {
		writeInt(0x4D546864);   	//MThd
		writeInt(6);		//Length
		writeShort(1);   		//Midi File Type
		writeShort(numberOfTracks);	    //Number of tracks
		writeShort(resolution);    	//Pulses Per Quarter Note
	}
	
	public void writeChunk(MidiOutputStream tempStream) throws IOException {
		writeInt(0x4D54726B); // Header
		writeInt(tempStream.size());
		tempStream.writeTo(this);
	}
	
	@Override
	public void close() {
		try {
			super.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public byte[] toByteArray() {
		return out instanceof ByteArrayOutputStream ? 
				((ByteArrayOutputStream)out).toByteArray() : null;
	}
	
	public void writeTo(MidiOutputStream mos) throws IOException {
		if (!(out instanceof ByteArrayOutputStream)) {
			throw new IllegalStateException("Underlying stream is no ByteArrayOutputStream");
		}
		((ByteArrayOutputStream)out).writeTo(mos);
	}
	
}
